Skip to content

Update AVB hash header image_size to match unpacked original_image_size.#9830

Open
kousu wants to merge 1 commit into
topjohnwu:masterfrom
kousu:preflash-validation-failed
Open

Update AVB hash header image_size to match unpacked original_image_size.#9830
kousu wants to merge 1 commit into
topjohnwu:masterfrom
kousu:preflash-validation-failed

Conversation

@kousu
Copy link
Copy Markdown

@kousu kousu commented Apr 27, 2026

Fixes #8389

@kousu kousu force-pushed the preflash-validation-failed branch 4 times, most recently from 360b9ce to 44363da Compare April 27, 2026 05:33
@kousu kousu force-pushed the preflash-validation-failed branch from 44363da to fe7c726 Compare April 27, 2026 05:48
@kousu
Copy link
Copy Markdown
Author

kousu commented Apr 27, 2026

Here's my proof that this works:

Build

My build env is ArchLinux with these packages (some of them from the AUR) as recommended:

android-sdk-build-tools r37.0.0-1
android-sdk-cmdline-tools-latest 20.0-1
android-platform 37.0_r01-1
android-tools 35.0.2-25
android-udev 20260423-1
jdk21-openjdk 21.0.11.u10-1

plus this helper script to avoid polluting Arch's packages with the forked NDK:

setup_ondk.sh
#!/usr/bin/env bash
# Install a single ONDK version.
# Usage:  sudo ./setup_ondk.sh <version>   e.g. sudo ./setup_ondk.sh r27.0
#
# The version is installed to /opt/android-sdk/ndk/ondk-<version>/ so multiple
# versions coexist.  test_bisect.sh selects the right one at each bisect step
# without needing sudo.
#
# Tarballs are downloaded to $CACHE_DIR (default ~/.cache/ondk relative to the
# invoking user) and kept so re-runs skip the download.

set -euo pipefail

NDK_ROOT="/opt/android-sdk/ndk"

# Run as sudo but use the invoking user's home for the tarball cache.
REAL_USER="${SUDO_USER:-$USER}"
REAL_HOME="$(getent passwd "$REAL_USER" | cut -d: -f6)"
CACHE_DIR="${ONDK_CACHE:-$REAL_HOME/.cache/ondk}"

VER="${1:?Usage: $0 <ondk-version>  e.g. $0 r27.0}"

mkdir -p "$NDK_ROOT"

# Download as the real user so the cache files are owned correctly.
sudo_download() {
    sudo -u "$REAL_USER" mkdir -p "$CACHE_DIR"
    sudo -u "$REAL_USER" wget -q --show-progress -O "$1" "$2"
}

DEST="$NDK_ROOT/ondk-$VER"
if [[ -f "$DEST/ONDK_VERSION" ]] && [[ "$(cat "$DEST/ONDK_VERSION")" == "$VER" ]]; then
    echo "=== ONDK $VER already installed, skipping ==="
else
    TARBALL="$CACHE_DIR/ondk-$VER-linux.tar.xz"
    if [[ ! -f "$TARBALL" ]]; then
        echo "=== Downloading ONDK $VER ==="
        URL="https://github.com/topjohnwu/ondk/releases/download/$VER/ondk-$VER-linux.tar.xz"
        sudo_download "$TARBALL.tmp" "$URL"
        mv "$TARBALL.tmp" "$TARBALL"
    else
        echo "=== Using cached tarball for ONDK $VER ==="
    fi

    echo "=== Installing ONDK $VER to $DEST ==="
    rm -rf "$DEST"
    mkdir -p "$DEST"
    tar xf "$TARBALL" --strip-components=1 -C "$DEST"
    echo "=== ONDK $VER installed ==="
fi
mksdk
#!/bin/sh

set -e

REQUIRED_ONDK=$1

SDK_ROOT=/opt/android-sdk
ONDK_DIR="$SDK_ROOT/ndk/ondk-$REQUIRED_ONDK"

if [ ! -d "$ONDK_DIR" ]; then
    HERE=$(cd "$(dirname "$0")"; pwd)
    sudo "$HERE/setup_ondk.sh" "$REQUIRED_ONDK"
fi

# Build a fake SDK root with a correctly-versioned ndk/magisk symlink.
FAKE_SDK="/tmp/android-sdk-odnk-$REQUIRED_ONDK"

mkdir -p "$FAKE_SDK/ndk"
ln -nsf "$ONDK_DIR" "$FAKE_SDK/ndk/magisk"
# Symlink all other top-level SDK dirs so the build can find them if needed.
for entry in "$SDK_ROOT"/*/; do
    name="$(basename "$entry")"
    [[ "$name" == "ndk" ]] && continue
    ln -nsf "$entry" "$FAKE_SDK/$name"
done

echo $FAKE_SDK

I'm on fe7c726

$ git rev-parse HEAD
fe7c72646ab4b4b6a6435e4bbb7514d5be55b3ee

Build (~15 minutes, maybe longer):

$ unset ANDROID_HOME
$ unset ANDROID_SDK
$ unset ANDROID_NDK
$ unset ANDROID_NDK_ROOT
$ JAVA_HOME=/usr/lib/jvm/java-21-openjdk/ ANDROID_SDK_ROOT=$(./mksdk r30.0) ./build.py --release all

* Building: magiskpolicy magisk magiskinit magiskboot


* Building the Magisk app

Note: /home/kousu/src/Magisk/app/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: /home/kousu/src/Magisk/app/shared/src/main/java/com/topjohnwu/magisk/StubApk.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: /home/kousu/src/Magisk/app/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

Output: out/app-release.apk


* Building the next generation Magisk app


Output: out/apk-ng-release.apk


* Building the test app


Output: out/test.apk

Let's double-check it compiled the expected version + git commit in:

$ /opt/android-sdk/build-tools/37.0.0/aapt dump badging  ./out/app-release.apk  | grep package
package: name='com.topjohnwu.magisk' versionCode='30700' versionName='fe7c7264' platformBuildVersionName='17' platformBuildVersionCode='37' compileSdkVersion='37' compileSdkVersionCodename='17'

👍

Install

$ adb devices
List of devices attached
**********	device
$ adb uninstall com.topjohnwu.magisk
Success
$ adb install out/app-release.apk 
Performing Streamed Install
Success

Notice that the app version is fe7c726 as expected:

image

Patch

$ curl -sJLO https://mirrorbits.lineageos.org/full/kiev/20260419/boot.img
$ sha256sum boot.img
877ac66398714af5a0fd5893dfd7a32bb164b3ec1ec46b8fb1fc792cb6e1ca5a  ../bisect-magisk/boot.img
$ adb push ../bisect-magisk/boot.img /sdcard/
../bisect-magisk/boot.img: 1 file pushed, 0 skipped. 71.6 MB/s (100663296 bytes in 1.342s)
image image
- Device platform: arm64-v8a
- Installing: fe7c7264 (30700)
- Copying image to cache
- Unpacking boot image
Parsing boot image: [/data/user_de/0/com.topjohnwu.magisk/install/boot.img]
HEADER_VER      [2]
KERNEL_SZ       [35237904]
RAMDISK_SZ      [1816233]
SECOND_SZ       [0]
RECOV_DTBO_SZ   [0]
DTB_SZ          [405853]
OS_VERSION      [15.0.0]
OS_PATCH_LEVEL  [2026-04]
PAGESIZE        [4096]
NAME            []
CMDLINE         [androidboot.console=ttyMSM0 androidboot.hardware=qcom androidboot.memcg=1 androidboot.usbcontroller=a600000.dwc3 cgroup.memory=nokmem,nosocket loop.max_part=7 lpm_levels.sleep_disabled=1 service_locator.enable=1 swiotlb=2048]
CHECKSUM        [1abf4254843044f3bf79ae254f7cc2c1f36bd024000000000000000000000000]
KERNEL_FMT      [raw]
RAMDISK_FMT     [gzip]
VBMETA
- Checking ramdisk status
Loading cpio: [ramdisk.cpio]
- Stock boot image detected
- Patching ramdisk
- Pre-init storage partition: sde9
Loading cpio: [ramdisk.cpio]
Add file [init] (100750)
Create directory [overlay.d] (0750)
Create directory [overlay.d/sbin] (0750)
Add file [overlay.d/sbin/magisk.xz] (100644)
Add file [overlay.d/sbin/stub.xz] (100644)
Add file [overlay.d/sbin/init-ld.xz] (100644)
Patch with flag KEEPVERITY=[true] KEEPFORCEENCRYPT=[true]
Loading cpio: [ramdisk.cpio.orig]
Backup [init] -> [.backup/init.xz]
Record new entry: [overlay.d] -> [.backup/.rmlist]
Record new entry: [overlay.d/sbin] -> [.backup/.rmlist]
Record new entry: [overlay.d/sbin/init-ld.xz] -> [.backup/.rmlist]
Record new entry: [overlay.d/sbin/magisk.xz] -> [.backup/.rmlist]
Record new entry: [overlay.d/sbin/stub.xz] -> [.backup/.rmlist]
Create directory [.backup] (0000)
Add file [.backup/.magisk] (100000)
Dumping cpio: [ramdisk.cpio]
Loading dtbs from [dtb]
Loading dtbs from [dtb]
Failed to patch
Failed to patch
Failed to patch
Parsing boot image: [/data/user_de/0/com.topjohnwu.magisk/install/boot.img]
HEADER_VER      [2]
- Repacking boot image
KERNEL_SZ       [35237904]
RAMDISK_SZ      [1816233]
SECOND_SZ       [0]
RECOV_DTBO_SZ   [0]
DTB_SZ          [405853]
OS_VERSION      [15.0.0]
OS_PATCH_LEVEL  [2026-04]
PAGESIZE        [4096]
NAME            []
CMDLINE         [androidboot.console=ttyMSM0 androidboot.hardware=qcom androidboot.memcg=1 androidboot.usbcontroller=a600000.dwc3 cgroup.memory=nokmem,nosocket loop.max_part=7 lpm_levels.sleep_disabled=1 service_locator.enable=1 swiotlb=2048]
CHECKSUM        [1abf4254843044f3bf79ae254f7cc2c1f36bd024000000000000000000000000]
KERNEL_FMT      [raw]
RAMDISK_FMT     [gzip]
VBMETA
Repack to boot image: [new-boot.img]
HEADER_VER      [2]
KERNEL_SZ       [35237904]
RAMDISK_SZ      [1655370]
SECOND_SZ       [0]
RECOV_DTBO_SZ   [0]
DTB_SZ          [405853]
OS_VERSION      [15.0.0]
OS_PATCH_LEVEL  [2026-04]
PAGESIZE        [4096]
NAME            []
CMDLINE         [androidboot.console=ttyMSM0 androidboot.hardware=qcom androidboot.memcg=1 androidboot.usbcontroller=a600000.dwc3 cgroup.memory=nokmem,nosocket loop.max_part=7 lpm_levels.sleep_disabled=1 service_locator.enable=1 swiotlb=2048]
CHECKSUM        [233e0b35cfe736892be3513296d91383a46a880a000000000000000000000000]

****************************
 Output file is written to 
 /storage/emulated/0/Download/magisk_patched-30700_iuojB.img 
****************************
cp: can't preserve ownership of 'busybox': Operation not permitted
cp: can't preserve ownership of 'init-ld': Operation not permitted
cp: can't preserve ownership of 'magisk': Operation not permitted
cp: can't preserve ownership of 'magiskboot': Operation not permitted
cp: can't preserve ownership of 'magiskinit': Operation not permitted
cp: can't preserve ownership of 'magiskpolicy': Operation not permitted
- All done!

Get the image back out so we can flash it.

$ adb pull /sdcard/Download/magisk_patched-30700_iuojB.img 
/sdcard/Download/magisk_patched-30700_iuojB.img: 1 file pulled, 0 skipped. 41.9 MB/s (100663296 bytes in 2.291s)
$ sha256sum magisk_patched-30700_iuojB.img   # this should ... probably be deterministic?
e3ab1c9d526b89dfc45cdc4115edcd9920afaff1af70caa2dbd0b3ca84d135ce  magisk_patched-30700_iuojB.img

Flash

🌟 Flashing gets past the dreaded " (bootloader) Preflash validation failed" 🐦‍⬛ 🐈‍⬛ 🏴 ☠️ 🌟

$ adb reboot bootloader
$ fastboot getvar product
product: kiev
Finished. Total time: 0.000s
$ fastboot getvar sku
sku: XT2113-2
Finished. Total time: 0.000s
$ fastboot getvar version-bootloader
version-bootloader: MBM-3.0-kiev_retail-45a34bc590e-220906
Finished. Total time: 0.000s
$ fastboot flash boot --slot all magisk_patched-30700_iuojB.img   ## FIXED 🎇🚀🧨🚀🧨🚀🧨🚀🎇
Sending 'boot_a' (98304 KB)                        OKAY [  2.105s]
Writing 'boot_a'                                   OKAY [  1.505s]
Sending 'boot_b' (98304 KB)                        OKAY [  2.077s]
Writing 'boot_b'                                   OKAY [  1.620s]
Finished. Total time: 7.311s
$ fastboot reboot 
Rebooting                                          OKAY [  0.000s]
Finished. Total time: 0.050s

Test

And it comes up cleanly with the right version,

image

and it's rooted 🎉

image

kousu added a commit to kousu/Magisk that referenced this pull request Apr 27, 2026
This follows topjohnwu#9830
with recomputing the AVB hash.

Apparently few (no?) devices actualy respect this hash in
the wild at the moment, but it is good to be prepared.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
kousu added a commit to kousu/Magisk that referenced this pull request Apr 27, 2026
This follows topjohnwu#9830
with recomputing the AVB hash.

Apparently few (no?) devices actualy respect this hash in
the wild at the moment, but it is good to be prepared.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
kousu added a commit to kousu/Magisk that referenced this pull request Apr 27, 2026
This follows topjohnwu#9830
by recomputing the AVB hash.

Apparently few (no?) devices actually respect this hash in
the wild at the moment, but it's good to be prepared.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread native/src/boot/bootimg.hpp
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates MagiskBoot’s AVB vbmeta handling during repack so the vbmeta hash descriptor’s image_size is synchronized with the repacked AOSP image size, addressing fastboot “Preflash validation failed” on some devices (e.g., Motorola).

Changes:

  • Add AVB descriptor tag/struct definitions and a small descriptor-iteration helper on AvbVBMetaImageHeader.
  • During repack, update AVB footer fields and additionally patch the vbmeta hash descriptor image_size to match the new original_image_size.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
native/src/boot/bootimg.hpp Adds AVB descriptor types plus a range/iterator helper to traverse vbmeta descriptors.
native/src/boot/bootimg.cpp Uses the new descriptor iteration to locate the hash descriptor and update image_size during repack.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread native/src/boot/bootimg.hpp
Comment thread native/src/boot/bootimg.hpp
Comment thread native/src/boot/bootimg.cpp
@kousu kousu force-pushed the preflash-validation-failed branch 2 times, most recently from ef7c484 to 81a674f Compare April 28, 2026 01:51
kousu added a commit to kousu/Magisk that referenced this pull request Apr 28, 2026
This follows topjohnwu#9830
by recomputing the AVB hash.

Apparently few (no?) devices actually respect this hash in
the wild at the moment, but it's good to be prepared.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kousu
Copy link
Copy Markdown
Author

kousu commented Apr 28, 2026

I've addressed co-pilot's reviews. They were a couple useful safety checks but nothing that changed the main direction of the logic. You could ask it for another round if you like 😽

Fixes topjohnwu#8389

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kousu kousu force-pushed the preflash-validation-failed branch from 81a674f to e9c673e Compare May 14, 2026 19:38
@kousu
Copy link
Copy Markdown
Author

kousu commented May 14, 2026

@yujincheng08 I'm wondering what's the usual timeline for getting a human review on PRs. I'd like to see this go in so that I can feel confident about updating my phone again and I'm sure so would everyone in #8389. Just an ETA so we can set our expectations and attention right would be great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flashing patched boot.img fails with (bootloader) Preflash validation failed

2 participants